<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ES6学习</title>
</head>
<body>
    <script>
        // ES6提供新的数据结构Set(集合)对象，类似于数组，但是成员的值都是唯一的，键不限于字符串，可以是对象，实现了iterator接口，可使用拓展运算符和for..of进行遍历
        // Set 结构的键名就是键值（两者是同一个值）
        let s = new Set();
        console.log(s,typeof s);
        let s2 = new Set(['早上','晚上','中午','下午','早上']);
        console.log(s2);
        s2.add('傍晚');
        s2.delete('下午');
        console.log(s2.has('晚上'));
        console.log(s2);

        for (let i of s2){
            console.log(i);
        }
        s2.clear();
        console.log(s2);

        // 对真实数组去重后再还原
        let arr1 = [1,2,3,4,5,3,2,1,0];
        const result = Array.from(new Set(arr1));
        const result1 = [...new Set(arr1)];
        console.log(result1,result);
        let arr2 = [3,5,6,5,3]
        // 交集
        // const result2 = [...new Set(arr1)].filter(item=>[...new Set(arr2)].includes(item));
        const result2 = [...new Set(arr1)].filter(item=>new Set(arr2).has(item))
        console.log(result2);
        //并集
        const result3 = [...new Set(arr1),...new Set(arr2)];
        console.log(result3)
        //数组差
        const result4 = [...new Set(arr1)].filter(item=>!([...new Set(arr2)].includes(item)))
        console.log(result4);

        // WeakSet的成员必须是对象，里面的对象都是弱引用，垃圾回收机制会自动回收该对象所占用的内存
        // WeakSet不能遍历，是因为成员都是弱引用，随时都可能消失，遍历机制无法保证成员的存在。
        const a = [[1,2],[3,4]];
        console.log(new WeakSet(a));

        // Map对象 Object结构提供'字符串-值'的对应，Map提供了'值——值'的对应，是一种更完善的Hash结构实现，需要“键值对”的数据结构，Map 比 Object 更合适。
        // Map的键实际上是跟内存地址绑定的,只要内存地址不一样就视为两个不一样的键
        const m = new Map();
        m.set(name,'zhangsan');

        console.log(m.get(name),m.has(name),m.delete(name));

        const items = [['height',1.88],['weight',90+'KG']]

        const m2 = new Map(items);
        console.log(m2,m2.size);
        console.log(m2.get('height'),m2.has('weight'));

        // 将数组中多个键值对放入一个Map，如果对一个键多次赋值，后面的值会覆盖前面的值。
        const m3 = new Map();
        items.forEach(([key,value])=>m3.set(key,value));
        console.log(m3,m3.size);
        m3.forEach((value,key,map)=>{
            console.log('KEY:%s,Value:%s',key,value)
        })

        // ES6的class可以视为ES5的语法糖
        // ES5构造对象的方法
        function Wine(water,sugar) {
            this.water = water;
            this.sugar = sugar;
        }
        Wine.prototype.call = function(){
            console.log('我喜欢喝酒！');
        }
        let beer = new Wine(90,'milkSugar')
        beer.call();
        console.log(beer);

        // ES6 Class实现 静态变量属于类不属于实例对象 非静态变量属于实例对象不属于类
        class Computer{
            // 静态变量
            static mouse = '雷蛇';
            // 非静态变量
            color = 'red';
            // 构造方法,名字不能修改
            constructor(brand,price) {
                this.brand = brand;
                this.price = price;
                let size = '1.5inch';
            }
            // 方法必须使用该语法，不能使用ES5的原型。
            call(){
                console.log('我可以玩电脑！');
            }
        }
        let sanxing = new Computer('三星',9999);
        sanxing.call();
        console.log(sanxing,sanxing.mouse,Computer.mouse,sanxing.color,Computer.color);

        // ES6的方法子类继承父类
        class SmartComputer extends Computer{
            constructor(brand,price,adress,time){
                super(brand,price);
                this.adress = adress;
                this.time = time;
            }
            watchVideo(){
                console.log('可以看电视！');
            }
            listenMusic(){
                console.log('可以听音乐！');
            }
            //可以完全重写父类方法，不能super调用父类方法
            call(){
                console.log('我是子类重写父类的Call方法！');
            }
        }
        let ipad = new SmartComputer('爱派德',7777,'America','2015-09-30');
        console.log(ipad);
        ipad.listenMusic();
        ipad.watchVideo();
        ipad.call();

        // class类的setter和getter方法
        class House{
            get price(){
                console.log('获取价格属性！');
                return '非常便宜';
            }
            set price(nowPrice){
                console.log('设置价格属性');
                return '设置房屋价格';
            }
        }
        const fangzi = new House();
        console.log(fangzi.price);
        console.log(fangzi.price = 999999);


        let a0={
            name:'a',
            test1:'1',
        }
        let b0 = {
            name:'b',
            test2:'2'
        }
        // Object.assign把原有的对象属性合并覆盖并成为被覆盖的对象。
        // console.log(Object.assign(a0,b0))
        // 设置b0原型是a0
        console.log(Object.setPrototypeOf(b0,a0))
        // 知道b0的原型是a0
        console.log(Object.getPrototypeOf(b0));

        // 模块化好处
        // 防止命名冲突
        // 代码复用
        // 高维护性

        const  p = new Promise((resolve,reject)=>{
             resolve('成功');
            // reject('失败');
        })
        async function main() {
            try{
                let abc = await p;
                console.log(abc);
            }catch (e) {
                console.log(e);
            }
        }
        main();


        // ES8对象拓展方法
        let food = {
            "tea":"blacktea",
            "meat":['beef','pork','fish','duck'],
            "vegetables":['leek','cabbage','celery','kale']
        }
        console.log(Object.keys(food),Object.values(food),Object.entries(food));
        // Object.entries便于生成一个map集合
        const map = new Map(Object.entries(food));
        console.log(map);
        // 对象属性的描述对象，用于模仿新建类似的对象
        console.log(Object.getOwnPropertyDescriptors(food));

        // ES9为对象也提供了rest参数和拓展运算符
        function book({name,price,publish,...information}) {
            console.log(name,price,publish,information);
        }
        book({name:'小螺号',price:956,publish:'黑马教育出版社',time:'2016-07-05',color:'purple',size:'5.0inch'});

        const skill1 = {
            q:'降龙十八掌'
        };
        const skill2 = {
            w:'佛山无影脚'
        };
        const skill3 = {
            e:'葵花点穴手'
        };
        const skill4 = {
            r:'排山倒海'
        };

        const allSkills = {...skill1,...skill2,...skill3,...skill4};
        console.log(allSkills);

        // ES9正则表达式分组拓展?<文本> 提取文本和URL
        let str = '<a href="www.baidu.com">百度</a>';
        const reg = /<a href="(.*)">(.*)<\/a>/;
        console.log(reg.exec(str),reg.exec(str)[1],reg.exec(str)[2]);
        // 有groups
        let str2 = '<a href="www.taobao.com">淘宝</a>';
        const reg2 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
        console.log(reg2.exec(str2),reg2.exec(str2).groups.url,reg2.exec(str2).groups.text);

        // 正则表达式的正向断言和反向断言
        let sentence = 'ABC123随便写写666哈哈哈';
        const reg3 = /\d+(?=哈)/;
        console.log(reg3.exec(sentence));
        const reg4 = /(?<=写)\d+/;
        console.log(reg4.exec(sentence));

        // 正则表达式的dotAll模式
        // dot . 元字符 除了换行符以外的任意单个字符
        let moban = `<ul>
                        <li>
                            <a>随便写写</a>
                            <p>填充文本</p>
                        </li>
                        <li>
                            <a>举个例子</a>
                            <p>快来匹配</p>
                        </li>
                       </ul>`
        const reg5 = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/g;
        const reg6 = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
        console.log(reg5.exec(moban));

        let res ;
        let array= new Array();
        console.log(reg6.exec(moban));
        while ( res = reg6.exec(moban)){
            array.push({title:res[1],description:res[2]});
        };
        console.log(array);

        // ES9Object.fromEntries()将二维数组转换回对象
        const abc = Object.fromEntries([
            ['hand','手'],
            ['foot','脚']
        ])
        console.log(abc);

        const mm = new Map();
        mm.set('age',22);
        console.log(mm,Object.fromEntries(mm));

        // ES9 trimStart trimLeft和trimEnd trimRight清除左侧或者右侧空白
        const ILOVEU = '  I love you    ';
        console.log(ILOVEU.trimLeft(),ILOVEU.trimStart());
        console.log(ILOVEU.trimRight(),ILOVEU.trimEnd());

        // ES9多维数组转为低维数组 低维展开
        const shuzu = [1,2,3,4,5,[6,7,[8,9]]];
        // 参数为深度,代表一个数字
        console.log(shuzu.flat(2));

        // flatMap 仍然保持一维数组
        const sz = [1,2,3,5,8];
        console.log(sz.map(item=>[item*30]).flat());
        console.log(sz.flatMap(item=>[item*30]));

        // 私有属性#
        class Person{
            name;
            #weight;
            #age;
            constructor(name,weight,age) {
                this.name = name;
                this.#age = age;
                this.#weight = weight;
            }
            introdution(){
                console.log(this.name,this.#age,this.#weight);
            }
        }

        let boy = new Person('小强','5KG',8);
        // console.log(boy.name,boy.#age,boy.#weight);不能在类外部获取私有变量
        boy.introdution();

        // Promise.allSettled()方法和Promise.all()方法返回Promise对象
        const p1 = new Promise((resolve, reject) =>{
            setTimeout(()=>{
                resolve('商品数据-1');
                // reject('出错了');
            },1000)
        });
        const p2 = new Promise((resolve, reject) =>{
            setTimeout(()=>{
                resolve('商品数据-2');
                // reject('出错了');
            },1000)
        });
        // 类似||和&&的关系 前者永远返回成功的Promise后者会返回失败的Promise
        console.log(Promise.allSettled([p1,p2]),Promise.all([p1,p2]));

        // matchAll方法
        const reg7 = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg;
        const total = moban.matchAll(reg7);
        for (let j of total){
            console.log(j);
        }
        console.log([...total]);


        // 可选链操作符 ?. import动态导入 import(路径).then(module=>{moudule.})
        function main(config) {
            let result = config&&config.cache&&config.cache.username;
            console.log(result);
        }
        main({
            db:{
                name:'mysql',
                port:'127.0.0.1'
            },
            cache:{
                host:'129.168.1.200',
                username:'admin'
            }
        })

        // 大数值运算
        let max = Number.MAX_SAFE_INTEGER;
        console.log(max,max+1,max+2);
        console.log(BigInt(max),BigInt(max)+BigInt(1),BigInt(max)+BigInt(2));

        console.log(globalThis)



    </script>

</body>
</html>